﻿using System;
using System.Collections.Generic;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms.Design;
using devtm.Editor.TypeSelector;
using DslModeling = global::Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling;
using System.Windows.Forms;
using System.Reflection;
using Mono.Cecil;
using CustomTypes.Mono.Extensions;

namespace devtm.AutoMapper
{
    public class ListeMemberEditor2 : UITypeEditor
    {

        protected DslModeling.Store Store;
        protected MapperShape Instance;

        public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
        {

            IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (edSvc != null)
            {

                bool isSource = context.PropertyDescriptor.Name.Contains("Source");

                if (context.Instance.GetType().IsArray)
                    Instance = ((Object[])context.Instance)[0] as MapperShape;
                else
                    Instance = context.Instance as MapperShape;

                Store = Instance.Store;
                Mapper mapper = GetMapper(context);
                TypeElement typeElement = GetTypeElement(context, mapper);
                using (CustomTypeRepository repository = CustomTypeRepository.Instance(typeElement.Store, false))
                {
                    var type = repository.GetType(typeElement.AssemblyQualifiedName);

                    TreeView control = new TreeView();

                    TreeNode t = new TreeNode() { Text = "Instance", Tag = "Instance", ToolTipText = "Instance" };

                    GetNodeMembers(type, t);
                    control.Nodes.Add(t);
                    t.Expand();

                    if (isSource)
                        BuildSubProperties(t);

                    int indx = 0;
                    if (!string.IsNullOrEmpty(value as string))
                    {
                        string[] tb = (value as string).Split('.');
                        FindProperty(tb, control, t, ref indx);
                    }

                    if (isSource)
                        control.BeforeExpand +=
                            (sender, e) =>
                            {
                                BuildSubProperties(e.Node);
                            };


                    var d = DateTime.Now;


                    

                    control.AfterSelect +=
                    (sender, e) =>
                    {

                        if (DateTime.Now.Subtract(d).Seconds < 1)
                            return;

                        try
                        {

                            if (value as string == control.SelectedNode.ToolTipText)
                                return;

                            value = control.SelectedNode.ToolTipText;

                        }
                        catch (Exception ex)
                        {
                            Helpers._output.WriteLine(ex.ToString());
                        }

                        if (sender != null)
                            if ((sender as TreeView).SelectedNode != null)
                                edSvc.CloseDropDown();

                    };

                    edSvc.DropDownControl(control);

                }

            }

            return value;

        }

        private void BuildSubProperties(TreeNode t)
        {
            foreach (TreeNode t2 in t.Nodes)
            {

                if (t2.Nodes.Count > 0)
                    continue;

                TypeReference type = null;
                PropertyDefinition p1 = t2.Tag as PropertyDefinition;

                if (p1 != null)
                    type = p1.TypeMember;
                else
                    type = (t2.Tag as FieldDefinition).TypeMember;

                if (type.Resolve().IsEnum)
                    continue;

                string n = type.FullName;

                if (!NewMapperHelper.types.Contains(n))
                    GetNodeMembers(type, t2);

            }
        }

        private void BuildSubProperty(TreeNode t)
        {

            if (t.Nodes.Count > 0)
                return;

            TypeReference type = null;
            PropertyDefinition p1 = t.Tag as PropertyDefinition;

            if (p1 != null)
                type = p1.TypeMember;
            else
                type = (t.Tag as FieldDefinition).TypeMember;

            if (type.Resolve().IsEnum)
                return;

            string n = type.FullName;

            if (!NewMapperHelper.types.Contains(n))
                GetNodeMembers(type, t);

        }

        private void FindProperty(string[] value, TreeView control, TreeNode t, ref int index)
        {

            foreach (TreeNode item in t.Nodes)
            {
         
                if (item.Text == value[index])
                {
                    control.SelectedNode = item;

                    if (index < value.Length - 1)
                    {
                        index++;

                        if (item.Nodes.Count == 0)
                            BuildSubProperty(item);


                        FindProperty(value, control, item, ref index);
                        
                    }
                    return;

                }
            }
        }

        private void GetNodeMembers(TypeReference type, TreeNode t)
        {

            TypeDefinition ty = type.Resolve();

            foreach (MemberReference item in ty.GetMembers(MemberTypes.Property | MemberTypes.Field, "", type))
            {

                if (item.IsProperty() || item.IsField())
                {
                    TreeNode t2 = new TreeNode()
                    {
                        Tag = item,
                        Text = item.Name,
                        ToolTipText = GetName(t, item as IMemberDefinition)
                    };

                    t.Nodes.Add(t2);

                }

            }

        }

        private static string GetName(TreeNode t, IMemberDefinition item)
        {
            if (t.ToolTipText == "this")
                return item.Name;

            return t.Tag != null && !string.IsNullOrEmpty(t.ToolTipText) ? t.ToolTipText + "." + item.Name : item.Name;
        }


        private static Mapper GetMapper(System.ComponentModel.ITypeDescriptorContext context)
        {
            MapperShape p1;

            if (context.Instance.GetType().IsArray)
                p1 = ((Object[])context.Instance)[0] as MapperShape;
            else
                p1 = context.Instance as MapperShape;

            Mapper mapper = p1.ModelElement as Mapper;

            return mapper;
        }


        public override bool IsDropDownResizable
        {
            get
            {
                return true;
            }
        }


        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {

            if (context != null)
            {

                if (context.Instance.GetType().IsArray)
                    Instance = ((Object[])context.Instance)[0] as MapperShape;
                else
                    Instance = context.Instance as MapperShape;

                if (Instance != null)
                {
                    Store = Instance.Store;
                    Mapper mapper = GetMapper(context);
                    TypeElement typeElement = GetTypeElement(context, mapper);

                    if (typeElement != null)
                    {
                        using (var repository = CustomTypeRepository.Instance(typeElement.Store, false))
                        {

                            var type = repository.GetType(typeElement.AssemblyQualifiedName);

                            if (type != null)
                                return UITypeEditorEditStyle.DropDown;

                        }
                    }
                }
            }

            return UITypeEditorEditStyle.None;
        }

        private static TypeElement GetTypeElement(System.ComponentModel.ITypeDescriptorContext context, Mapper mapper)
        {
            if (context.PropertyDescriptor.Name.Contains("Source"))
                return mapper.MappingSource.TypeElement;

            if (mapper.MappingDestination != null)
                return mapper.MappingDestination.TypeElement;

            return null;

        }


    }
}
